package com.yizisu.playerlibrary.impl

import com.yizisu.playerlibrary.view.video_view.helper.logI
import kotlinx.coroutines.*
import kotlin.coroutines.EmptyCoroutineContext

/**
 * 自动循环任务
 */
internal class TickTask(
    val time: Long,
    val onThread: Boolean = false,
    val runnable: suspend CoroutineScope.() -> Unit
) {
    companion object {
        /**
         * 启动轮询,必须手动取消，否则内存泄露
         */
        fun start(
            time: Long = 1000L,
            onThread: Boolean = false,
            block: suspend CoroutineScope.() -> Unit
        ): TickTask {
            return TickTask(time, onThread, block).also {
                it.start()
            }
        }

        /**
         * 停止轮询
         */
        fun TickTask.stop() {
            cancel()
        }
    }

    private val coroutineScope = CoroutineScope(EmptyCoroutineContext)

    /**
     * job
     *
     */
    private var job: Job? = null

    /**
     * run
     */
    @Synchronized
    fun start() {
        if (isRunning) {
            logI("exopalyer TickTask已经启动,无需再启动")
            return
        }
        val block: suspend CoroutineScope.() -> Unit = {
            while (isActive) {
                runnable.invoke(this)
                delay(time)
            }
        }
        job = if (onThread) {
            coroutineScope.launch(block = block, context = Dispatchers.IO)
        } else {
            coroutineScope.launch(block = block, context = Dispatchers.Main)
        }
    }

    /**
     * 是否正运行
     */
    val isRunning
        get() = job?.isActive == true

    /**
     * 取消回调
     */
    fun cancel() {
        onlyCancelJob()
        job = null
    }

    /**
     * 生命周期可见
     */
    fun onStart() {
        //如果取消的时候正在运行，则自动恢复
        //如果用户取消，job是null，否则是自动取消，需要恢复
        if (job != null) {
            logI("exopalyer onStart 自动恢复TickTask")
            start()
        }
    }

    /**
     * 生命周期不可见
     */
    fun onStop() {
        onlyCancelJob()
    }

    fun onDestroy() {
        cancel()
        if (coroutineScope.isActive) {
            coroutineScope.cancel()
        }
    }

    /**
     * 取消job，变量不赋值为null，
     */
    private fun onlyCancelJob() {
        if (isRunning) {
            job?.cancel()
        }
    }
}
